/*!
 * mincart
 * The Mini Cart is a great way to improve your PayPal shopping cart integration.
 *
 * @version 3.0.6
 * @author Jeff Harrell <https://github.com/jeffharrell/>
 * @url http://www.mincartjs.com/
 * @license MIT <https://github.com/jeffharrell/mincart/raw/master/LICENSE.md>
 */

;
(function e(t, n, r) {
  function s(o, u) {
    if (!n[o]) {
      if (!t[o]) {
        var a = typeof require == "function" && require;
        if (!u && a) return a(o, !0);
        if (i) return i(o, !0);
        throw new Error("Cannot find module '" + o + "'")
      }
      var f = n[o] = {
        exports: {}
      };
      t[o][0].call(f.exports, function (e) {
        var n = t[o][1][e];
        return s(n ? n : e)
      }, f, f.exports, e, t, n, r)
    }
    return n[o].exports
  }
  var i = typeof require == "function" && require;
  for (var o = 0; o < r.length; o++) s(r[o]);
  return s
})({
  1: [function (require, module, exports) {


    //
    // The shims in this file are not fully implemented shims for the ES5
    // features, but do work for the particular use cases there is in
    // the other modules.
    //

    var toString = Object.prototype.toString;
    var hasOwnProperty = Object.prototype.hasOwnProperty;

    // Array.isArray is supported in IE9
    function isArray(xs) {
      return toString.call(xs) === '[object Array]';
    }
    exports.isArray = typeof Array.isArray === 'function' ? Array.isArray : isArray;

    // Array.prototype.indexOf is supported in IE9
    exports.indexOf = function indexOf(xs, x) {
      if (xs.indexOf) return xs.indexOf(x);
      for (var i = 0; i < xs.length; i++) {
        if (x === xs[i]) return i;
      }
      return -1;
    };

    // Array.prototype.filter is supported in IE9
    exports.filter = function filter(xs, fn) {
      if (xs.filter) return xs.filter(fn);
      var res = [];
      for (var i = 0; i < xs.length; i++) {
        if (fn(xs[i], i, xs)) res.push(xs[i]);
      }
      return res;
    };

    // Array.prototype.forEach is supported in IE9
    exports.forEach = function forEach(xs, fn, self) {
      if (xs.forEach) return xs.forEach(fn, self);
      for (var i = 0; i < xs.length; i++) {
        fn.call(self, xs[i], i, xs);
      }
    };

    // Array.prototype.map is supported in IE9
    exports.map = function map(xs, fn) {
      if (xs.map) return xs.map(fn);
      var out = new Array(xs.length);
      for (var i = 0; i < xs.length; i++) {
        out[i] = fn(xs[i], i, xs);
      }
      return out;
    };

    // Array.prototype.reduce is supported in IE9
    exports.reduce = function reduce(array, callback, opt_initialValue) {
      if (array.reduce) return array.reduce(callback, opt_initialValue);
      var value, isValueSet = false;

      if (2 < arguments.length) {
        value = opt_initialValue;
        isValueSet = true;
      }
      for (var i = 0, l = array.length; l > i; ++i) {
        if (array.hasOwnProperty(i)) {
          if (isValueSet) {
            value = callback(value, array[i], i, array);
          } else {
            value = array[i];
            isValueSet = true;
          }
        }
      }

      return value;
    };

    // String.prototype.substr - negative index don't work in IE8
    if ('ab'.substr(-1) !== 'b') {
      exports.substr = function (str, start, length) {
        // did we get a negative start, calculate how much it is from the beginning of the string
        if (start < 0) start = str.length + start;

        // call the original function
        return str.substr(start, length);
      };
    } else {
      exports.substr = function (str, start, length) {
        return str.substr(start, length);
      };
    }

    // String.prototype.trim is supported in IE9
    exports.trim = function (str) {
      if (str.trim) return str.trim();
      return str.replace(/^\s+|\s+$/g, '');
    };

    // Function.prototype.bind is supported in IE9
    exports.bind = function () {
      var args = Array.prototype.slice.call(arguments);
      var fn = args.shift();
      if (fn.bind) return fn.bind.apply(fn, args);
      var self = args.shift();
      return function () {
        fn.apply(self, args.concat([Array.prototype.slice.call(arguments)]));
      };
    };

    // Object.create is supported in IE9
    function create(prototype, properties) {
      var object;
      if (prototype === null) {
        object = {
          '__proto__': null
        };
      } else {
        if (typeof prototype !== 'object') {
          throw new TypeError(
            'typeof prototype[' + (typeof prototype) + '] != \'object\''
          );
        }
        var Type = function () {};
        Type.prototype = prototype;
        object = new Type();
        object.__proto__ = prototype;
      }
      if (typeof properties !== 'undefined' && Object.defineProperties) {
        Object.defineProperties(object, properties);
      }
      return object;
    }
    exports.create = typeof Object.create === 'function' ? Object.create : create;

    // Object.keys and Object.getOwnPropertyNames is supported in IE9 however
    // they do show a description and number property on Error objects
    function notObject(object) {
      return ((typeof object != "object" && typeof object != "function") || object === null);
    }

    function keysShim(object) {
      if (notObject(object)) {
        throw new TypeError("Object.keys called on a non-object");
      }

      var result = [];
      for (var name in object) {
        if (hasOwnProperty.call(object, name)) {
          result.push(name);
        }
      }
      return result;
    }

    // getOwnPropertyNames is almost the same as Object.keys one key feature
    //  is that it returns hidden properties, since that can't be implemented,
    //  this feature gets reduced so it just shows the length property on arrays
    function propertyShim(object) {
      if (notObject(object)) {
        throw new TypeError("Object.getOwnPropertyNames called on a non-object");
      }

      var result = keysShim(object);
      if (exports.isArray(object) && exports.indexOf(object, 'length') === -1) {
        result.push('length');
      }
      return result;
    }

    var keys = typeof Object.keys === 'function' ? Object.keys : keysShim;
    var getOwnPropertyNames = typeof Object.getOwnPropertyNames === 'function' ?
      Object.getOwnPropertyNames : propertyShim;

    if (new Error().hasOwnProperty('description')) {
      var ERROR_PROPERTY_FILTER = function (obj, array) {
        if (toString.call(obj) === '[object Error]') {
          array = exports.filter(array, function (name) {
            return name !== 'description' && name !== 'number' && name !== 'message';
          });
        }
        return array;
      };

      exports.keys = function (object) {
        return ERROR_PROPERTY_FILTER(object, keys(object));
      };
      exports.getOwnPropertyNames = function (object) {
        return ERROR_PROPERTY_FILTER(object, getOwnPropertyNames(object));
      };
    } else {
      exports.keys = keys;
      exports.getOwnPropertyNames = getOwnPropertyNames;
    }

    // Object.getOwnPropertyDescriptor - supported in IE8 but only on dom elements
    function valueObject(value, key) {
      return {
        value: value[key]
      };
    }

    if (typeof Object.getOwnPropertyDescriptor === 'function') {
      try {
        Object.getOwnPropertyDescriptor({
          'a': 1
        }, 'a');
        exports.getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
      } catch (e) {
        // IE8 dom element issue - use a try catch and default to valueObject
        exports.getOwnPropertyDescriptor = function (value, key) {
          try {
            return Object.getOwnPropertyDescriptor(value, key);
          } catch (e) {
            return valueObject(value, key);
          }
        };
      }
    } else {
      exports.getOwnPropertyDescriptor = valueObject;
    }

  }, {}],
  2: [function (require, module, exports) {

    // not implemented
    // The reason for having an empty file and not throwing is to allow
    // untraditional implementation of this module.

  }, {}],
  3: [function (require, module, exports) {
    var process = require("__browserify_process"); // Copyright Joyent, Inc. and other Node contributors.
    //
    // Permission is hereby granted, free of charge, to any person obtaining a
    // copy of this software and associated documentation files (the
    // "Software"), to deal in the Software without restriction, including
    // without limitation the rights to use, copy, modify, merge, publish,
    // distribute, sublicense, and/or sell copies of the Software, and to permit
    // persons to whom the Software is furnished to do so, subject to the
    // following conditions:
    //
    // The above copyright notice and this permission notice shall be included
    // in all copies or substantial portions of the Software.
    //
    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
    // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
    // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
    // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
    // USE OR OTHER DEALINGS IN THE SOFTWARE.

    var util = require('util');
    var shims = require('_shims');

    // resolves . and .. elements in a path array with directory names there
    // must be no slashes, empty elements, or device names (c:\) in the array
    // (so also no leading and trailing slashes - it does not distinguish
    // relative and absolute paths)
    function normalizeArray(parts, allowAboveRoot) {
      // if the path tries to go above the root, `up` ends up > 0
      var up = 0;
      for (var i = parts.length - 1; i >= 0; i--) {
        var last = parts[i];
        if (last === '.') {
          parts.splice(i, 1);
        } else if (last === '..') {
          parts.splice(i, 1);
          up++;
        } else if (up) {
          parts.splice(i, 1);
          up--;
        }
      }

      // if the path is allowed to go above the root, restore leading ..s
      if (allowAboveRoot) {
        for (; up--; up) {
          parts.unshift('..');
        }
      }

      return parts;
    }

    // Split a filename into [root, dir, basename, ext], unix version
    // 'root' is just a slash, or nothing.
    var splitPathRe =
      /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
    var splitPath = function (filename) {
      return splitPathRe.exec(filename).slice(1);
    };

    // path.resolve([from ...], to)
    // posix version
    exports.resolve = function () {
      var resolvedPath = '',
        resolvedAbsolute = false;

      for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
        var path = (i >= 0) ? arguments[i] : process.cwd();

        // Skip empty and invalid entries
        if (!util.isString(path)) {
          throw new TypeError('Arguments to path.resolve must be strings');
        } else if (!path) {
          continue;
        }

        resolvedPath = path + '/' + resolvedPath;
        resolvedAbsolute = path.charAt(0) === '/';
      }

      // At this point the path should be resolved to a full absolute path, but
      // handle relative paths to be safe (might happen when process.cwd() fails)

      // Normalize the path
      resolvedPath = normalizeArray(shims.filter(resolvedPath.split('/'), function (p) {
        return !!p;
      }), !resolvedAbsolute).join('/');

      return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
    };

    // path.normalize(path)
    // posix version
    exports.normalize = function (path) {
      var isAbsolute = exports.isAbsolute(path),
        trailingSlash = shims.substr(path, -1) === '/';

      // Normalize the path
      path = normalizeArray(shims.filter(path.split('/'), function (p) {
        return !!p;
      }), !isAbsolute).join('/');

      if (!path && !isAbsolute) {
        path = '.';
      }
      if (path && trailingSlash) {
        path += '/';
      }

      return (isAbsolute ? '/' : '') + path;
    };

    // posix version
    exports.isAbsolute = function (path) {
      return path.charAt(0) === '/';
    };

    // posix version
    exports.join = function () {
      var paths = Array.prototype.slice.call(arguments, 0);
      return exports.normalize(shims.filter(paths, function (p, index) {
        if (!util.isString(p)) {
          throw new TypeError('Arguments to path.join must be strings');
        }
        return p;
      }).join('/'));
    };


    // path.relative(from, to)
    // posix version
    exports.relative = function (from, to) {
      from = exports.resolve(from).substr(1);
      to = exports.resolve(to).substr(1);

      function trim(arr) {
        var start = 0;
        for (; start < arr.length; start++) {
          if (arr[start] !== '') break;
        }

        var end = arr.length - 1;
        for (; end >= 0; end--) {
          if (arr[end] !== '') break;
        }

        if (start > end) return [];
        return arr.slice(start, end - start + 1);
      }

      var fromParts = trim(from.split('/'));
      var toParts = trim(to.split('/'));

      var length = Math.min(fromParts.length, toParts.length);
      var samePartsLength = length;
      for (var i = 0; i < length; i++) {
        if (fromParts[i] !== toParts[i]) {
          samePartsLength = i;
          break;
        }
      }

      var outputParts = [];
      for (var i = samePartsLength; i < fromParts.length; i++) {
        outputParts.push('..');
      }

      outputParts = outputParts.concat(toParts.slice(samePartsLength));

      return outputParts.join('/');
    };

    exports.sep = '/';
    exports.delimiter = ':';

    exports.dirname = function (path) {
      var result = splitPath(path),
        root = result[0],
        dir = result[1];

      if (!root && !dir) {
        // No dirname whatsoever
        return '.';
      }

      if (dir) {
        // It has a dirname, strip trailing slash
        dir = dir.substr(0, dir.length - 1);
      }

      return root + dir;
    };


    exports.basename = function (path, ext) {
      var f = splitPath(path)[2];
      // TODO: make this comparison case-insensitive on windows?
      if (ext && f.substr(-1 * ext.length) === ext) {
        f = f.substr(0, f.length - ext.length);
      }
      return f;
    };


    exports.extname = function (path) {
      return splitPath(path)[3];
    };

  }, {
    "__browserify_process": 5,
    "_shims": 1,
    "util": 4
  }],
  4: [function (require, module, exports) {
    // Copyright Joyent, Inc. and other Node contributors.
    //
    // Permission is hereby granted, free of charge, to any person obtaining a
    // copy of this software and associated documentation files (the
    // "Software"), to deal in the Software without restriction, including
    // without limitation the rights to use, copy, modify, merge, publish,
    // distribute, sublicense, and/or sell copies of the Software, and to permit
    // persons to whom the Software is furnished to do so, subject to the
    // following conditions:
    //
    // The above copyright notice and this permission notice shall be included
    // in all copies or substantial portions of the Software.
    //
    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
    // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
    // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
    // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
    // USE OR OTHER DEALINGS IN THE SOFTWARE.

    var shims = require('_shims');

    var formatRegExp = /%[sdj%]/g;
    exports.format = function (f) {
      if (!isString(f)) {
        var objects = [];
        for (var i = 0; i < arguments.length; i++) {
          objects.push(inspect(arguments[i]));
        }
        return objects.join(' ');
      }

      var i = 1;
      var args = arguments;
      var len = args.length;
      var str = String(f).replace(formatRegExp, function (x) {
        if (x === '%%') return '%';
        if (i >= len) return x;
        switch (x) {
          case '%s':
            return String(args[i++]);
          case '%d':
            return Number(args[i++]);
          case '%j':
            try {
              return JSON.stringify(args[i++]);
            } catch (_) {
              return '[Circular]';
            }
          default:
            return x;
        }
      });
      for (var x = args[i]; i < len; x = args[++i]) {
        if (isNull(x) || !isObject(x)) {
          str += ' ' + x;
        } else {
          str += ' ' + inspect(x);
        }
      }
      return str;
    };

    /**
     * Echos the value of a value. Trys to print the value out
     * in the best way possible given the different types.
     *
     * @param {Object} obj The object to print out.
     * @param {Object} opts Optional options object that alters the output.
     */
    /* legacy: obj, showHidden, depth, colors*/
    function inspect(obj, opts) {
      // default options
      var ctx = {
        seen: [],
        stylize: stylizeNoColor
      };
      // legacy...
      if (arguments.length >= 3) ctx.depth = arguments[2];
      if (arguments.length >= 4) ctx.colors = arguments[3];
      if (isBoolean(opts)) {
        // legacy...
        ctx.showHidden = opts;
      } else if (opts) {
        // got an "options" object
        exports._extend(ctx, opts);
      }
      // set default options
      if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
      if (isUndefined(ctx.depth)) ctx.depth = 2;
      if (isUndefined(ctx.colors)) ctx.colors = false;
      if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
      if (ctx.colors) ctx.stylize = stylizeWithColor;
      return formatValue(ctx, obj, ctx.depth);
    }
    exports.inspect = inspect;


    // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
    inspect.colors = {
      'bold': [1, 22],
      'italic': [3, 23],
      'underline': [4, 24],
      'inverse': [7, 27],
      'white': [37, 39],
      'grey': [90, 39],
      'black': [30, 39],
      'blue': [34, 39],
      'cyan': [36, 39],
      'green': [32, 39],
      'magenta': [35, 39],
      'red': [31, 39],
      'yellow': [33, 39]
    };

    // Don't use 'blue' not visible on cmd.exe
    inspect.styles = {
      'special': 'cyan',
      'number': 'yellow',
      'boolean': 'yellow',
      'undefined': 'grey',
      'null': 'bold',
      'string': 'green',
      'date': 'magenta',
      // "name": intentionally not styling
      'regexp': 'red'
    };


    function stylizeWithColor(str, styleType) {
      var style = inspect.styles[styleType];

      if (style) {
        return '\u001b[' + inspect.colors[style][0] + 'm' + str +
          '\u001b[' + inspect.colors[style][1] + 'm';
      } else {
        return str;
      }
    }


    function stylizeNoColor(str, styleType) {
      return str;
    }


    function arrayToHash(array) {
      var hash = {};

      shims.forEach(array, function (val, idx) {
        hash[val] = true;
      });

      return hash;
    }


    function formatValue(ctx, value, recurseTimes) {
      // Provide a hook for user-specified inspect functions.
      // Check that value is an object with an inspect function on it
      if (ctx.customInspect &&
        value &&
        isFunction(value.inspect) &&
        // Filter out the util module, it's inspect function is special
        value.inspect !== exports.inspect &&
        // Also filter out any prototype objects using the circular check.
        !(value.constructor && value.constructor.prototype === value)) {
        var ret = value.inspect(recurseTimes);
        if (!isString(ret)) {
          ret = formatValue(ctx, ret, recurseTimes);
        }
        return ret;
      }

      // Primitive types cannot have properties
      var primitive = formatPrimitive(ctx, value);
      if (primitive) {
        return primitive;
      }

      // Look up the keys of the object.
      var keys = shims.keys(value);
      var visibleKeys = arrayToHash(keys);

      if (ctx.showHidden) {
        keys = shims.getOwnPropertyNames(value);
      }

      // Some type of object without properties can be shortcutted.
      if (keys.length === 0) {
        if (isFunction(value)) {
          var name = value.name ? ': ' + value.name : '';
          return ctx.stylize('[Function' + name + ']', 'special');
        }
        if (isRegExp(value)) {
          return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
        }
        if (isDate(value)) {
          return ctx.stylize(Date.prototype.toString.call(value), 'date');
        }
        if (isError(value)) {
          return formatError(value);
        }
      }

      var base = '',
        array = false,
        braces = ['{', '}'];

      // Make Array say that they are Array
      if (isArray(value)) {
        array = true;
        braces = ['[', ']'];
      }

      // Make functions say that they are functions
      if (isFunction(value)) {
        var n = value.name ? ': ' + value.name : '';
        base = ' [Function' + n + ']';
      }

      // Make RegExps say that they are RegExps
      if (isRegExp(value)) {
        base = ' ' + RegExp.prototype.toString.call(value);
      }

      // Make dates with properties first say the date
      if (isDate(value)) {
        base = ' ' + Date.prototype.toUTCString.call(value);
      }

      // Make error with message first say the error
      if (isError(value)) {
        base = ' ' + formatError(value);
      }

      if (keys.length === 0 && (!array || value.length == 0)) {
        return braces[0] + base + braces[1];
      }

      if (recurseTimes < 0) {
        if (isRegExp(value)) {
          return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
        } else {
          return ctx.stylize('[Object]', 'special');
        }
      }

      ctx.seen.push(value);

      var output;
      if (array) {
        output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
      } else {
        output = keys.map(function (key) {
          return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
        });
      }

      ctx.seen.pop();

      return reduceToSingleString(output, base, braces);
    }


    function formatPrimitive(ctx, value) {
      if (isUndefined(value))
        return ctx.stylize('undefined', 'undefined');
      if (isString(value)) {
        var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
          .replace(/'/g, "\\'")
          .replace(/\\"/g, '"') + '\'';
        return ctx.stylize(simple, 'string');
      }
      if (isNumber(value))
        return ctx.stylize('' + value, 'number');
      if (isBoolean(value))
        return ctx.stylize('' + value, 'boolean');
      // For some reason typeof null is "object", so special case here.
      if (isNull(value))
        return ctx.stylize('null', 'null');
    }


    function formatError(value) {
      return '[' + Error.prototype.toString.call(value) + ']';
    }


    function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
      var output = [];
      for (var i = 0, l = value.length; i < l; ++i) {
        if (hasOwnProperty(value, String(i))) {
          output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
            String(i), true));
        } else {
          output.push('');
        }
      }

      shims.forEach(keys, function (key) {
        if (!key.match(/^\d+$/)) {
          output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
            key, true));
        }
      });
      return output;
    }


    function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
      var name, str, desc;
      desc = shims.getOwnPropertyDescriptor(value, key) || {
        value: value[key]
      };
      if (desc.get) {
        if (desc.set) {
          str = ctx.stylize('[Getter/Setter]', 'special');
        } else {
          str = ctx.stylize('[Getter]', 'special');
        }
      } else {
        if (desc.set) {
          str = ctx.stylize('[Setter]', 'special');
        }
      }

      if (!hasOwnProperty(visibleKeys, key)) {
        name = '[' + key + ']';
      }
      if (!str) {
        if (shims.indexOf(ctx.seen, desc.value) < 0) {
          if (isNull(recurseTimes)) {
            str = formatValue(ctx, desc.value, null);
          } else {
            str = formatValue(ctx, desc.value, recurseTimes - 1);
          }
          if (str.indexOf('\n') > -1) {
            if (array) {
              str = str.split('\n').map(function (line) {
                return '  ' + line;
              }).join('\n').substr(2);
            } else {
              str = '\n' + str.split('\n').map(function (line) {
                return '   ' + line;
              }).join('\n');
            }
          }
        } else {
          str = ctx.stylize('[Circular]', 'special');
        }
      }
      if (isUndefined(name)) {
        if (array && key.match(/^\d+$/)) {
          return str;
        }
        name = JSON.stringify('' + key);
        if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
          name = name.substr(1, name.length - 2);
          name = ctx.stylize(name, 'name');
        } else {
          name = name.replace(/'/g, "\\'")
            .replace(/\\"/g, '"')
            .replace(/(^"|"$)/g, "'");
          name = ctx.stylize(name, 'string');
        }
      }

      return name + ': ' + str;
    }


    function reduceToSingleString(output, base, braces) {
      var numLinesEst = 0;
      var length = shims.reduce(output, function (prev, cur) {
        numLinesEst++;
        if (cur.indexOf('\n') >= 0) numLinesEst++;
        return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
      }, 0);

      if (length > 60) {
        return braces[0] +
          (base === '' ? '' : base + '\n ') +
          ' ' +
          output.join(',\n  ') +
          ' ' +
          braces[1];
      }

      return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
    }


    // NOTE: These type checking functions intentionally don't use `instanceof`
    // because it is fragile and can be easily faked with `Object.create()`.
    function isArray(ar) {
      return shims.isArray(ar);
    }
    exports.isArray = isArray;

    function isBoolean(arg) {
      return typeof arg === 'boolean';
    }
    exports.isBoolean = isBoolean;

    function isNull(arg) {
      return arg === null;
    }
    exports.isNull = isNull;

    function isNullOrUndefined(arg) {
      return arg == null;
    }
    exports.isNullOrUndefined = isNullOrUndefined;

    function isNumber(arg) {
      return typeof arg === 'number';
    }
    exports.isNumber = isNumber;

    function isString(arg) {
      return typeof arg === 'string';
    }
    exports.isString = isString;

    function isSymbol(arg) {
      return typeof arg === 'symbol';
    }
    exports.isSymbol = isSymbol;

    function isUndefined(arg) {
      return arg === void 0;
    }
    exports.isUndefined = isUndefined;

    function isRegExp(re) {
      return isObject(re) && objectToString(re) === '[object RegExp]';
    }
    exports.isRegExp = isRegExp;

    function isObject(arg) {
      return typeof arg === 'object' && arg;
    }
    exports.isObject = isObject;

    function isDate(d) {
      return isObject(d) && objectToString(d) === '[object Date]';
    }
    exports.isDate = isDate;

    function isError(e) {
      return isObject(e) && objectToString(e) === '[object Error]';
    }
    exports.isError = isError;

    function isFunction(arg) {
      return typeof arg === 'function';
    }
    exports.isFunction = isFunction;

    function isPrimitive(arg) {
      return arg === null ||
        typeof arg === 'boolean' ||
        typeof arg === 'number' ||
        typeof arg === 'string' ||
        typeof arg === 'symbol' || // ES6 symbol
        typeof arg === 'undefined';
    }
    exports.isPrimitive = isPrimitive;

    function isBuffer(arg) {
      return arg && typeof arg === 'object' &&
        typeof arg.copy === 'function' &&
        typeof arg.fill === 'function' &&
        typeof arg.binarySlice === 'function';
    }
    exports.isBuffer = isBuffer;

    function objectToString(o) {
      return Object.prototype.toString.call(o);
    }


    function pad(n) {
      return n < 10 ? '0' + n.toString(10) : n.toString(10);
    }


    var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
      'Oct', 'Nov', 'Dec'
    ];

    // 26 Feb 16:19:34
    function timestamp() {
      var d = new Date();
      var time = [pad(d.getHours()),
        pad(d.getMinutes()),
        pad(d.getSeconds())
      ].join(':');
      return [d.getDate(), months[d.getMonth()], time].join(' ');
    }


    // log is just a thin wrapper to console.log that prepends a timestamp
    exports.log = function () {
      console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments));
    };


    /**
     * Inherit the prototype methods from one constructor into another.
     *
     * The Function.prototype.inherits from lang.js rewritten as a standalone
     * function (not on Function.prototype). NOTE: If this file is to be loaded
     * during bootstrapping this function needs to be rewritten using some native
     * functions as prototype setup using normal JavaScript does not work as
     * expected during bootstrapping (see mirror.js in r114903).
     *
     * @param {function} ctor Constructor function which needs to inherit the
     *     prototype.
     * @param {function} superCtor Constructor function to inherit prototype from.
     */
    exports.inherits = function (ctor, superCtor) {
      ctor.super_ = superCtor;
      ctor.prototype = shims.create(superCtor.prototype, {
        constructor: {
          value: ctor,
          enumerable: false,
          writable: true,
          configurable: true
        }
      });
    };

    exports._extend = function (origin, add) {
      // Don't do anything if add isn't an object
      if (!add || !isObject(add)) return origin;

      var keys = shims.keys(add);
      var i = keys.length;
      while (i--) {
        origin[keys[i]] = add[keys[i]];
      }
      return origin;
    };

    function hasOwnProperty(obj, prop) {
      return Object.prototype.hasOwnProperty.call(obj, prop);
    }

  }, {
    "_shims": 1
  }],
  5: [function (require, module, exports) {
    // shim for using process in browser

    var process = module.exports = {};

    process.nextTick = (function () {
      var canSetImmediate = typeof window !== 'undefined' &&
        window.setImmediate;
      var canPost = typeof window !== 'undefined' &&
        window.postMessage && window.addEventListener;

      if (canSetImmediate) {
        return function (f) {
          return window.setImmediate(f)
        };
      }

      if (canPost) {
        var queue = [];
        window.addEventListener('message', function (ev) {
          var source = ev.source;
          if ((source === window || source === null) && ev.data === 'process-tick') {
            ev.stopPropagation();
            if (queue.length > 0) {
              var fn = queue.shift();
              fn();
            }
          }
        }, true);

        return function nextTick(fn) {
          queue.push(fn);
          window.postMessage('process-tick', '*');
        };
      }

      return function nextTick(fn) {
        setTimeout(fn, 0);
      };
    })();

    process.title = 'browser';
    process.browser = true;
    process.env = {};
    process.argv = [];

    process.binding = function (name) {
      throw new Error('process.binding is not supported');
    }

    // TODO(shtylman)
    process.cwd = function () {
      return '/'
    };
    process.chdir = function (dir) {
      throw new Error('process.chdir is not supported');
    };

  }, {}],
  6: [function (require, module, exports) {

    /*!
     * EJS
     * Copyright(c) 2012 TJ Holowaychuk <tj@vision-media.ca>
     * MIT Licensed
     */

    /**
     * Module dependencies.
     */

    var utils = require('./utils'),
      path = require('path'),
      dirname = path.dirname,
      extname = path.extname,
      join = path.join,
      fs = require('fs'),
      read = fs.readFileSync;

    /**
     * Filters.
     *
     * @type Object
     */

    var filters = exports.filters = require('./filters');

    /**
     * Intermediate js cache.
     *
     * @type Object
     */

    var cache = {};

    /**
     * Clear intermediate js cache.
     *
     * @api public
     */

    exports.clearCache = function () {
      cache = {};
    };

    /**
     * Translate filtered code into function calls.
     *
     * @param {String} js
     * @return {String}
     * @api private
     */

    function filtered(js) {
      return js.substr(1).split('|').reduce(function (js, filter) {
        var parts = filter.split(':'),
          name = parts.shift(),
          args = parts.join(':') || '';
        if (args) args = ', ' + args;
        return 'filters.' + name + '(' + js + args + ')';
      });
    };

    /**
     * Re-throw the given `err` in context to the
     * `str` of ejs, `filename`, and `lineno`.
     *
     * @param {Error} err
     * @param {String} str
     * @param {String} filename
     * @param {String} lineno
     * @api private
     */

    function rethrow(err, str, filename, lineno) {
      var lines = str.split('\n'),
        start = Math.max(lineno - 3, 0),
        end = Math.min(lines.length, lineno + 3);

      // Error context
      var context = lines.slice(start, end).map(function (line, i) {
        var curr = i + start + 1;
        return (curr == lineno ? ' >> ' : '    ') +
          curr +
          '| ' +
          line;
      }).join('\n');

      // Alter exception message
      err.path = filename;
      err.message = (filename || 'ejs') + ':' +
        lineno + '\n' +
        context + '\n\n' +
        err.message;

      throw err;
    }

    /**
     * Parse the given `str` of ejs, returning the function body.
     *
     * @param {String} str
     * @return {String}
     * @api public
     */

    var parse = exports.parse = function (str, options) {
      var options = options || {},
        open = options.open || exports.open || '<%',
        close = options.close || exports.close || '%>',
        filename = options.filename,
        compileDebug = options.compileDebug !== false,
        buf = "";

      buf += 'var buf = [];';
      if (false !== options._with) buf += '\nwith (locals || {}) { (function(){ ';
      buf += '\n buf.push(\'';

      var lineno = 1;

      var consumeEOL = false;
      for (var i = 0, len = str.length; i < len; ++i) {
        var stri = str[i];
        if (str.slice(i, open.length + i) == open) {
          i += open.length

          var prefix, postfix, line = (compileDebug ? '__stack.lineno=' : '') + lineno;
          switch (str[i]) {
            case '=':
              prefix = "', escape((" + line + ', ';
              postfix = ")), '";
              ++i;
              break;
            case '-':
              prefix = "', (" + line + ', ';
              postfix = "), '";
              ++i;
              break;
            default:
              prefix = "');" + line + ';';
              postfix = "; buf.push('";
          }

          var end = str.indexOf(close, i),
            js = str.substring(i, end),
            start = i,
            include = null,
            n = 0;

          if ('-' == js[js.length - 1]) {
            js = js.substring(0, js.length - 2);
            consumeEOL = true;
          }

          if (0 == js.trim().indexOf('include')) {
            var name = js.trim().slice(7).trim();
            if (!filename) throw new Error('filename option is required for includes');
            var path = resolveInclude(name, filename);
            include = read(path, 'utf8');
            include = exports.parse(include, {
              filename: path,
              _with: false,
              open: open,
              close: close,
              compileDebug: compileDebug
            });
            buf += "' + (function(){" + include + "})() + '";
            js = '';
          }

          while (~(n = js.indexOf("\n", n))) n++, lineno++;
          if (js.substr(0, 1) == ':') js = filtered(js);
          if (js) {
            if (js.lastIndexOf('//') > js.lastIndexOf('\n')) js += '\n';
            buf += prefix;
            buf += js;
            buf += postfix;
          }
          i += end - start + close.length - 1;

        } else if (stri == "\\") {
          buf += "\\\\";
        } else if (stri == "'") {
          buf += "\\'";
        } else if (stri == "\r") {
          // ignore
        } else if (stri == "\n") {
          if (consumeEOL) {
            consumeEOL = false;
          } else {
            buf += "\\n";
            lineno++;
          }
        } else {
          buf += stri;
        }
      }

      if (false !== options._with) buf += "'); })();\n} \nreturn buf.join('');";
      else buf += "');\nreturn buf.join('');";
      return buf;
    };

    /**
     * Compile the given `str` of ejs into a `Function`.
     *
     * @param {String} str
     * @param {Object} options
     * @return {Function}
     * @api public
     */

    var compile = exports.compile = function (str, options) {
      options = options || {};
      var escape = options.escape || utils.escape;

      var input = JSON.stringify(str),
        compileDebug = options.compileDebug !== false,
        client = options.client,
        filename = options.filename ?
        JSON.stringify(options.filename) :
        'undefined';

      if (compileDebug) {
        // Adds the fancy stack trace meta info
        str = [
          'var __stack = { lineno: 1, input: ' + input + ', filename: ' + filename + ' };',
          rethrow.toString(),
          'try {',
          exports.parse(str, options),
          '} catch (err) {',
          '  rethrow(err, __stack.input, __stack.filename, __stack.lineno);',
          '}'
        ].join("\n");
      } else {
        str = exports.parse(str, options);
      }

      if (options.debug) console.log(str);
      if (client) str = 'escape = escape || ' + escape.toString() + ';\n' + str;

      try {
        var fn = new Function('locals, filters, escape, rethrow', str);
      } catch (err) {
        if ('SyntaxError' == err.name) {
          err.message += options.filename ?
            ' in ' + filename :
            ' while compiling ejs';
        }
        throw err;
      }

      if (client) return fn;

      return function (locals) {
        return fn.call(this, locals, filters, escape, rethrow);
      }
    };

    /**
     * Render the given `str` of ejs.
     *
     * Options:
     *
     *   - `locals`          Local variables object
     *   - `cache`           Compiled functions are cached, requires `filename`
     *   - `filename`        Used by `cache` to key caches
     *   - `scope`           Function execution context
     *   - `debug`           Output generated function body
     *   - `open`            Open tag, defaulting to "<%"
     *   - `close`           Closing tag, defaulting to "%>"
     *
     * @param {String} str
     * @param {Object} options
     * @return {String}
     * @api public
     */

    exports.render = function (str, options) {
      var fn, options = options || {};

      if (options.cache) {
        if (options.filename) {
          fn = cache[options.filename] || (cache[options.filename] = compile(str, options));
        } else {
          throw new Error('"cache" option requires "filename".');
        }
      } else {
        fn = compile(str, options);
      }

      options.__proto__ = options.locals;
      return fn.call(options.scope, options);
    };

    /**
     * Render an EJS file at the given `path` and callback `fn(err, str)`.
     *
     * @param {String} path
     * @param {Object|Function} options or callback
     * @param {Function} fn
     * @api public
     */

    exports.renderFile = function (path, options, fn) {
      var key = path + ':string';

      if ('function' == typeof options) {
        fn = options, options = {};
      }

      options.filename = path;

      var str;
      try {
        str = options.cache ?
          cache[key] || (cache[key] = read(path, 'utf8')) :
          read(path, 'utf8');
      } catch (err) {
        fn(err);
        return;
      }
      fn(null, exports.render(str, options));
    };

    /**
     * Resolve include `name` relative to `filename`.
     *
     * @param {String} name
     * @param {String} filename
     * @return {String}
     * @api private
     */

    function resolveInclude(name, filename) {
      var path = join(dirname(filename), name);
      var ext = extname(name);
      if (!ext) path += '.ejs';
      return path;
    }

    // express support

    exports.__express = exports.renderFile;

    /**
     * Expose to require().
     */

    if (require.extensions) {
      require.extensions['.ejs'] = function (module, filename) {
        filename = filename || module.filename;
        var options = {
            filename: filename,
            client: true
          },
          template = fs.readFileSync(filename).toString(),
          fn = compile(template, options);
        module._compile('module.exports = ' + fn.toString() + ';', filename);
      };
    } else if (require.registerExtension) {
      require.registerExtension('.ejs', function (src) {
        return compile(src, {});
      });
    }

  }, {
    "./filters": 7,
    "./utils": 8,
    "fs": 2,
    "path": 3
  }],
  7: [function (require, module, exports) {
    /*!
     * EJS - Filters
     * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
     * MIT Licensed
     */

    /**
     * First element of the target `obj`.
     */

    exports.first = function (obj) {
      return obj[0];
    };

    /**
     * Last element of the target `obj`.
     */

    exports.last = function (obj) {
      return obj[obj.length - 1];
    };

    /**
     * Capitalize the first letter of the target `str`.
     */

    exports.capitalize = function (str) {
      str = String(str);
      return str[0].toUpperCase() + str.substr(1, str.length);
    };

    /**
     * Downcase the target `str`.
     */

    exports.downcase = function (str) {
      return String(str).toLowerCase();
    };

    /**
     * Uppercase the target `str`.
     */

    exports.upcase = function (str) {
      return String(str).toUpperCase();
    };

    /**
     * Sort the target `obj`.
     */

    exports.sort = function (obj) {
      return Object.create(obj).sort();
    };

    /**
     * Sort the target `obj` by the given `prop` ascending.
     */

    exports.sort_by = function (obj, prop) {
      return Object.create(obj).sort(function (a, b) {
        a = a[prop], b = b[prop];
        if (a > b) return 1;
        if (a < b) return -1;
        return 0;
      });
    };

    /**
     * Size or length of the target `obj`.
     */

    exports.size = exports.length = function (obj) {
      return obj.length;
    };

    /**
     * Add `a` and `b`.
     */

    exports.plus = function (a, b) {
      return Number(a) + Number(b);
    };

    /**
     * Subtract `b` from `a`.
     */

    exports.minus = function (a, b) {
      return Number(a) - Number(b);
    };

    /**
     * Multiply `a` by `b`.
     */

    exports.times = function (a, b) {
      return Number(a) * Number(b);
    };

    /**
     * Divide `a` by `b`.
     */

    exports.divided_by = function (a, b) {
      return Number(a) / Number(b);
    };

    /**
     * Join `obj` with the given `str`.
     */

    exports.join = function (obj, str) {
      return obj.join(str || ', ');
    };

    /**
     * Truncate `str` to `len`.
     */

    exports.truncate = function (str, len, append) {
      str = String(str);
      if (str.length > len) {
        str = str.slice(0, len);
        if (append) str += append;
      }
      return str;
    };

    /**
     * Truncate `str` to `n` words.
     */

    exports.truncate_words = function (str, n) {
      var str = String(str),
        words = str.split(/ +/);
      return words.slice(0, n).join(' ');
    };

    /**
     * Replace `pattern` with `substitution` in `str`.
     */

    exports.replace = function (str, pattern, substitution) {
      return String(str).replace(pattern, substitution || '');
    };

    /**
     * Prepend `val` to `obj`.
     */

    exports.prepend = function (obj, val) {
      return Array.isArray(obj) ? [val].concat(obj) :
        val + obj;
    };

    /**
     * Append `val` to `obj`.
     */

    exports.append = function (obj, val) {
      return Array.isArray(obj) ?
        obj.concat(val) :
        obj + val;
    };

    /**
     * Map the given `prop`.
     */

    exports.map = function (arr, prop) {
      return arr.map(function (obj) {
        return obj[prop];
      });
    };

    /**
     * Reverse the given `obj`.
     */

    exports.reverse = function (obj) {
      return Array.isArray(obj) ?
        obj.reverse() :
        String(obj).split('').reverse().join('');
    };

    /**
     * Get `prop` of the given `obj`.
     */

    exports.get = function (obj, prop) {
      return obj[prop];
    };

    /**
     * Packs the given `obj` into json string
     */
    exports.json = function (obj) {
      return JSON.stringify(obj);
    };

  }, {}],
  8: [function (require, module, exports) {

    /*!
     * EJS
     * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
     * MIT Licensed
     */

    /**
     * Escape the given string of `html`.
     *
     * @param {String} html
     * @return {String}
     * @api private
     */

    exports.escape = function (html) {
      return String(html)
        .replace(/&(?!#?[a-zA-Z0-9]+;)/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/'/g, '&#39;')
        .replace(/"/g, '&quot;');
    };


  }, {}],
  9: [function (require, module, exports) {
    'use strict';


    var Product = require('./product'),
      Pubsub = require('./util/pubsub'),
      Storage = require('./util/storage'),
      constants = require('./constants'),
      currency = require('./util/currency'),
      mixin = require('./util/mixin');



    /**
     * Renders the Mini Cart to the page's DOM.
     *
     * @constructor
     * @param {string} name Name of the cart (used as a key for storage)
     * @param {duration} number Time in milliseconds that the cart data should persist
     */
    function Cart(name, duration) {
      var data, items, settings, len, i;

      this._items = [];
      this._settings = {
        bn: constants.BN
      };

      Pubsub.call(this);
      Storage.call(this, name, duration);

      if ((data = this.load())) {
        items = data.items;
        settings = data.settings;

        if (settings) {
          this._settings = settings;
        }

        if (items) {
          for (i = 0, len = items.length; i < len; i++) {
            this.add(items[i]);
          }
        }
      }
    }


    mixin(Cart.prototype, Pubsub.prototype);
    mixin(Cart.prototype, Storage.prototype);


    /**
     * Adds an item to the cart. This fires an "add" event.
     *
     * @param {object} data Item data
     * @return {number} Item location in the cart
     */
    Cart.prototype.add = function add(data) {
      var that = this,
        items = this.items(),
        idx = false,
        isExisting = false,
        product, key, len, i;

      // Prune cart settings data from the product
      for (key in data) {
        if (constants.SETTINGS.test(key)) {
          this._settings[key] = data[key];
          delete data[key];
        }
      }

      // Look to see if the same product has already been added
      for (i = 0, len = items.length; i < len; i++) {
        if (items[i].isEqual(data)) {
          product = items[i];
          product.set('quantity', product.get('quantity') + (parseInt(data.quantity, 10) || 1));
          idx = i;
          isExisting = true;
          break;
        }
      }

      // If not, then try to add it
      if (!product) {
        product = new Product(data);

        if (product.isValid()) {
          idx = (this._items.push(product) - 1);

          product.on('change', function (key, value) {
            that.save();
            that.fire('change', idx, key, value);
          });

          this.save();
        }
      }

      if (product) {
        this.fire('add', idx, product, isExisting);
      }

      return idx;
    };


    /**
     * Returns the carts current items.
     *
     * @param {number} idx (Optional) Returns only that item.
     * @return {array|object}
     */
    Cart.prototype.items = function get(idx) {
      return (typeof idx === 'number') ? this._items[idx] : this._items;
    };


    /**
     * Returns the carts current settings.
     *
     * @param {string} name (Optional) Returns only that setting.
     * @return {array|string}
     */
    Cart.prototype.settings = function settings(name) {
      return (name) ? this._settings[name] : this._settings;
    };


    /**
     * Returns the cart discount.
     *
     * @param {object} config (Optional) Currency formatting options.
     * @return {number|string}
     */
    Cart.prototype.discount = function discount(config) {
      var result = parseFloat(this.settings('discount_amount_cart')) || 0;

      if (!result) {
        result = (parseFloat(this.settings('discount_rate_cart')) || 0) * this.subtotal() / 100;
      }

      config = config || {};
      config.currency = this.settings('currency_code');

      return currency(result, config);
    };


    /**
     * Returns the cart total without discounts.
     *
     * @param {object} config (Optional) Currency formatting options.
     * @return {number|string}
     */
    Cart.prototype.subtotal = function subtotal(config) {
      var products = this.items(),
        result = 0,
        i, len;

      for (i = 0, len = products.length; i < len; i++) {
        result += products[i].total();
      }

      config = config || {};
      config.currency = this.settings('currency_code');

      return currency(result, config);
    };


    /**
     * Returns the cart total.
     *
     * @param {object} config (Optional) Currency formatting options.
     * @return {number|string}
     */
    Cart.prototype.total = function total(config) {
      var result = 0;

      result += this.subtotal();
      result -= this.discount();

      config = config || {};
      config.currency = this.settings('currency_code');

      return currency(result, config);
    };


    /**
     * Remove an item from the cart. This fires a "remove" event.
     *
     * @param {number} idx Item index to remove.
     * @return {boolean}
     */
    Cart.prototype.remove = function remove(idx) {
      var item = this._items.splice(idx, 1);

      if (this._items.length === 0) {
        this.destroy();
      }

      if (item) {
        this.save();
        this.fire('remove', idx, item[0]);
      }

      return !!item.length;
    };


    /**
     * Saves the cart data.
     */
    Cart.prototype.save = function save() {
      var items = this.items(),
        settings = this.settings(),
        data = [],
        i, len;

      for (i = 0, len = items.length; i < len; i++) {
        data.push(items[i].get());
      }

      Storage.prototype.save.call(this, {
        items: data,
        settings: settings
      });
    };


    /**
     * Proxies the new_checkout event
     * The assumption is the view triggers this and consumers subscribe to it
     *
     * @param {object} The initiating event
     */
    Cart.prototype.new_checkout = function new_checkout(evt) {
      this.fire('new_checkout', evt);
    };


    /**
     * Destroy the cart data. This fires a "destroy" event.
     */
    Cart.prototype.destroy = function destroy() {
      Storage.prototype.destroy.call(this);

      this._items = [];
      this._settings = {
        bn: constants.BN
      };

      this.fire('destroy');
    };




    module.exports = Cart;

  }, {
    "./constants": 11,
    "./product": 13,
    "./util/currency": 15,
    "./util/mixin": 18,
    "./util/pubsub": 19,
    "./util/storage": 20
  }],
  10: [function (require, module, exports) {
    'use strict';


    var mixin = require('./util/mixin');


    var defaults = module.exports = {

      name: 'staplesbmincart',

      parent: (typeof document !== 'undefined') ? document.body : null,

      action: 'checkout.html',

      target: '',

      duration: 30,

      template: '<%var items = cart.items();var settings = cart.settings();var hasItems = !!items.length;var priceFormat = { format: true, currency: cart.settings("currency_code") };var totalFormat = { format: true, showCode: true };%><form method="post" class="<% if (!hasItems) { %>sbmincart-empty<% } %>" action="<%= config.action %>" target="<%= config.target %>">    <button type="button" class="sbmincart-closer">&times;</button>    <ul>        <% for (var i= 0, idx = i + 1, len = items.length; i < len; i++, idx++) { %>        <li class="sbmincart-item">            <div class="sbmincart-details-name">                <a class="sbmincart-name" href="<%= items[i].get("href") %>"><%= items[i].get("hub_item") %></a>                <ul class="sbmincart-attributes">                    <% if (items[i].get("item_number")) { %>                    <li>                        <%= items[i].get("item_number") %>                        <input type="hidden" name="item_number_<%= idx %>" value="<%= items[i].get("item_number") %>" />                    </li>                    <% } %>                    <% if (items[i].discount()) { %>                    <li>                        <%= config.strings.discount %> <%= items[i].discount(priceFormat) %>                        <input type="hidden" name="discount_amount_<%= idx %>" value="<%= items[i].discount() %>" />                    </li>                    <% } %>                    <% for (var options = items[i].options(), j = 0, len2 = options.length; j < len2; j++) { %>                        <li>                            <%= options[j].key %>: <%= options[j].value %>                            <input type="hidden" name="on<%= j %>_<%= idx %>" value="<%= options[j].key %>" />                            <input type="hidden" name="os<%= j %>_<%= idx %>" value="<%= options[j].value %>" />                        </li>                    <% } %>                </ul>            </div>            <div class="sbmincart-details-quantity">                <input class="sbmincart-quantity" data-sbmincart-idx="<%= i %>" name="quantity_<%= idx %>" type="text" pattern="[0-9]*" value="<%= items[i].get("quantity") %>" autocomplete="off" />            </div>            <div class="sbmincart-details-remove">                <button type="button" class="sbmincart-remove" data-sbmincart-idx="<%= i %>">&times;</button>            </div>            <div class="sbmincart-details-price">                <span class="sbmincart-price"><%= items[i].total(priceFormat) %></span>            </div>            <input type="hidden" name="hub_item_<%= idx %>" value="<%= items[i].get("hub_item") %>" />            <input type="hidden" name="amount_<%= idx %>" value="<%= items[i].amount() %>" />            <input type="hidden" name="shipping_<%= idx %>" value="<%= items[i].get("shipping") %>" />            <input type="hidden" name="shipping2_<%= idx %>" value="<%= items[i].get("shipping2") %>" />        </li>        <% } %>    </ul>    <div class="sbmincart-footer">        <% if (hasItems) { %>            <div class="sbmincart-subtotal">                <%= config.strings.subtotal %> <%= cart.total(totalFormat) %>            </div>            <button class="sbmincart-submit" type="submit" data-sbmincart-alt="<%= config.strings.buttonAlt %>"><%- config.strings.button %></button>        <% } else { %>            <p class="sbmincart-empty-text"><%= config.strings.empty %></p>        <% } %>    </div>    <input type="hidden" name="cmd" value="_cart" />    <input type="hidden" name="upload" value="1" />    <% for (var key in settings) { %>        <input type="hidden" name="<%= key %>" value="<%= settings[key] %>" />    <% } %></form>',

      styles: '',

      strings: {
        button: 'Check Out',
        subtotal: 'Subtotal:',
        discount: 'Discount:',
        empty: 'Your shopping cart is empty'
      }

    };


    /**
     * Mixes in the user config with the default config.
     *
     * @param {object} userConfig Configuration overrides
     * @return {object}
     */
    module.exports.load = function load(userConfig) {
      return mixin(defaults, userConfig);
    };

  }, {
    "./util/mixin": 18
  }],
  11: [function (require, module, exports) {
    'use strict';


    module.exports = {

      COMMANDS: {
        _cart: true,
        _xclick: true,
        _donations: true
      },

      SETTINGS: /^(?:business|currency_code|lc|paymentaction|no_shipping|cn|no_note|invoice|handling_cart|weight_cart|weight_unit|tax_cart|discount_amount_cart|discount_rate_cart|page_style|image_url|cpp_|cs|cbt|return|cancel_return|notify_url|rm|custom|charset)/,

      BN: 'sbmincart_AddToCart_WPS_US',

      KEYUP_TIMEOUT: 500,

      SHOWING_CLASS: 'sbmincart-showing',

      REMOVE_CLASS: 'sbmincart-remove',

      CLOSER_CLASS: 'sbmincart-closer',

      QUANTITY_CLASS: 'sbmincart-quantity',

      ITEM_CLASS: 'sbmincart-item',

      ITEM_CHANGED_CLASS: 'sbmincart-item-changed',

      SUBMIT_CLASS: 'sbmincart-submit',

      DATA_IDX: 'data-sbmincart-idx'

    };

  }, {}],
  12: [function (require, module, exports) {
    'use strict';


    var Cart = require('./cart'),
      View = require('./view'),
      config = require('./config'),
      sbmincart = {},
      cartModel,
      confModel,
      viewModel;


    /**
     * Renders the Mini Cart to the page's DOM.
     *
     * @param {object} userConfig Configuration overrides
     */
    sbmincart.render = function (userConfig) {
      confModel = sbmincart.config = config.load(userConfig);
      cartModel = sbmincart.cart = new Cart(confModel.name, confModel.duration);
      viewModel = sbmincart.view = new View({
        config: confModel,
        cart: cartModel
      });

      cartModel.on('add', viewModel.addItem, viewModel);
      cartModel.on('change', viewModel.changeItem, viewModel);
      cartModel.on('remove', viewModel.removeItem, viewModel);
      cartModel.on('destroy', viewModel.hide, viewModel);
    };


    /**
     * Resets the Mini Cart and its view model
     */
    sbmincart.reset = function () {
      cartModel.destroy();

      viewModel.hide();
      viewModel.redraw();
    };




    // Export to either node or the brower window
    if (typeof window === 'undefined') {
      module.exports = sbmincart;
    } else {
      if (!window.paypal) {
        window.paypal = {};
      }

      window.hub = sbmincart;
    }

  }, {
    "./cart": 9,
    "./config": 10,
    "./view": 22
  }],
  13: [function (require, module, exports) {
    'use strict';


    var currency = require('./util/currency'),
      Pubsub = require('./util/pubsub'),
      mixin = require('./util/mixin');


    var parser = {
      quantity: function (value) {
        value = parseInt(value, 10);

        if (isNaN(value) || !value) {
          value = 1;
        }

        return value;
      },
      amount: function (value) {
        return parseFloat(value) || 0;
      },
      href: function (value) {
        if (value) {
          return value;
        } else {
          return (typeof window !== 'undefined') ? window.location.href : null;
        }
      }
    };


    /**
     * Creates a new product.
     *
     * @constructor
     * @param {object} data Item data
     */
    function Product(data) {
      data.quantity = parser.quantity(data.quantity);
      data.amount = parser.amount(data.amount);
      data.href = parser.href(data.href);

      this._data = data;
      this._options = null;
      this._discount = null;
      this._amount = null;
      this._total = null;

      Pubsub.call(this);
    }


    mixin(Product.prototype, Pubsub.prototype);


    /**
     * Gets the product data.
     *
     * @param {string} key (Optional) A key to restrict the returned data to.
     * @return {array|string}
     */
    Product.prototype.get = function get(key) {
      return (key) ? this._data[key] : this._data;
    };


    /**
     * Sets a value on the product. This is used rather than manually setting the
     * value so that we can fire a "change" event.
     *
     * @param {string} key
     * @param {string} value
     */
    Product.prototype.set = function set(key, value) {
      var setter = parser[key];

      this._data[key] = setter ? setter(value) : value;
      this._options = null;
      this._discount = null;
      this._amount = null;
      this._total = null;

      this.fire('change', key);
    };


    /**
     * Parse and return the options for this product.
     *
     * @return {object}
     */
    Product.prototype.options = function options() {
      var result, key, value, amount, i, j;

      if (!this._options) {
        result = [];
        i = 0;

        while ((key = this.get('on' + i))) {
          value = this.get('os' + i);
          amount = 0;
          j = 0;

          while (typeof this.get('option_select' + j) !== 'undefined') {
            if (this.get('option_select' + j) === value) {
              amount = parser.amount(this.get('option_amount' + j));
              break;
            }

            j++;
          }

          result.push({
            key: key,
            value: value,
            amount: amount
          });

          i++;
        }

        this._options = result;
      }

      return this._options;
    };


    /**
     * Parse and return the discount for this product.
     *
     * @param {object} config (Optional) Currency formatting options.
     * @return {number|string}
     */
    Product.prototype.discount = function discount(config) {
      var flat, rate, num, limit, result, amount;

      if (!this._discount) {
        result = 0;
        num = parseInt(this.get('discount_num'), 10) || 0;
        limit = Math.max(num, this.get('quantity') - 1);

        if (this.get('discount_amount') !== undefined) {
          flat = parser.amount(this.get('discount_amount'));
          result += flat;
          result += parser.amount(this.get('discount_amount2') || flat) * limit;
        } else if (this.get('discount_rate') !== undefined) {
          rate = parser.amount(this.get('discount_rate'));
          amount = this.amount();

          result += rate * amount / 100;
          result += parser.amount(this.get('discount_rate2') || rate) * amount * limit / 100;
        }

        this._discount = result;
      }

      return currency(this._discount, config);
    };


    /**
     * Parse and return the total without discounts for this product.
     *
     * @param {object} config (Optional) Currency formatting options.
     * @return {number|string}
     */
    Product.prototype.amount = function amount(config) {
      var result, options, len, i;

      if (!this._amount) {
        result = this.get('amount');
        options = this.options();

        for (i = 0, len = options.length; i < len; i++) {
          result += options[i].amount;
        }

        this._amount = result;
      }

      return currency(this._amount, config);
    };


    /**
     * Parse and return the total for this product.
     *
     * @param {object} config (Optional) Currency formatting options.
     * @return {number|string}
     */
    Product.prototype.total = function total(config) {
      var result;

      if (!this._total) {
        result = this.get('quantity') * this.amount();
        result -= this.discount();

        this._total = parser.amount(result);
      }

      return currency(this._total, config);
    };


    /**
     * Determine if this product has the same data as another.
     *
     * @param {object|Product} data Other product.
     * @return {boolean}
     */
    Product.prototype.isEqual = function isEqual(data) {
      var match = false;

      if (data instanceof Product) {
        data = data._data;
      }

      if (this.get('hub_item') === data.hub_item) {
        if (this.get('item_number') === data.item_number) {
          if (this.get('amount') === parser.amount(data.amount)) {
            var i = 0;

            match = true;

            while (typeof data['os' + i] !== 'undefined') {
              if (this.get('os' + i) !== data['os' + i]) {
                match = false;
                break;
              }

              i++;
            }
          }
        }
      }

      return match;
    };


    /**
     * Determine if this product is valid.
     *
     * @return {boolean}
     */
    Product.prototype.isValid = function isValid() {
      return (this.get('hub_item') && this.amount() > 0);
    };


    /**
     * Destroys this product. Fires a "destroy" event.
     */
    Product.prototype.destroy = function destroy() {
      this._data = [];
      this.fire('destroy', this);
    };




    module.exports = Product;

  }, {
    "./util/currency": 15,
    "./util/mixin": 18,
    "./util/pubsub": 19
  }],
  14: [function (require, module, exports) {
    /* jshint quotmark:double */


    "use strict";



    module.exports.add = function add(el, str) {
      var re;

      if (!el) {
        return false;
      }

      if (el && el.classList && el.classList.add) {
        el.classList.add(str);
      } else {
        re = new RegExp("\\b" + str + "\\b");

        if (!re.test(el.className)) {
          el.className += " " + str;
        }
      }
    };


    module.exports.remove = function remove(el, str) {
      var re;

      if (!el) {
        return false;
      }

      if (el.classList && el.classList.add) {
        el.classList.remove(str);
      } else {
        re = new RegExp("\\b" + str + "\\b");

        if (re.test(el.className)) {
          el.className = el.className.replace(re, "");
        }
      }
    };


    module.exports.inject = function inject(el, str) {
      var style;

      if (!el) {
        return false;
      }

      if (str) {
        style = document.createElement("style");
        style.type = "text/css";

        if (style.styleSheet) {
          style.styleSheet.cssText = str;
        } else {
          style.appendChild(document.createTextNode(str));
        }

        el.appendChild(style);
      }
    };

  }, {}],
  15: [function (require, module, exports) {
    'use strict';


    var currencies = {
      AED: {
        before: '\u062c'
      },
      ANG: {
        before: '\u0192'
      },
      ARS: {
        before: '$',
        code: true
      },
      AUD: {
        before: '$',
        code: true
      },
      AWG: {
        before: '\u0192'
      },
      BBD: {
        before: '$',
        code: true
      },
      BGN: {
        before: '\u043b\u0432'
      },
      BMD: {
        before: '$',
        code: true
      },
      BND: {
        before: '$',
        code: true
      },
      BRL: {
        before: 'R$'
      },
      BSD: {
        before: '$',
        code: true
      },
      CAD: {
        before: '$',
        code: true
      },
      CHF: {
        before: '',
        code: true
      },
      CLP: {
        before: '$',
        code: true
      },
      CNY: {
        before: '\u00A5'
      },
      COP: {
        before: '$',
        code: true
      },
      CRC: {
        before: '\u20A1'
      },
      CZK: {
        before: 'Kc'
      },
      DKK: {
        before: 'kr'
      },
      DOP: {
        before: '$',
        code: true
      },
      EEK: {
        before: 'kr'
      },
      EUR: {
        before: '\u20AC'
      },
      GBP: {
        before: '\u00A3'
      },
      GTQ: {
        before: 'Q'
      },
      HKD: {
        before: '$',
        code: true
      },
      HRK: {
        before: 'kn'
      },
      HUF: {
        before: 'Ft'
      },
      IDR: {
        before: 'Rp'
      },
      ILS: {
        before: '\u20AA'
      },
      INR: {
        before: 'Rs.'
      },
      ISK: {
        before: 'kr'
      },
      JMD: {
        before: 'J$'
      },
      JPY: {
        before: '\u00A5'
      },
      KRW: {
        before: '\u20A9'
      },
      KYD: {
        before: '$',
        code: true
      },
      LTL: {
        before: 'Lt'
      },
      LVL: {
        before: 'Ls'
      },
      MXN: {
        before: '$',
        code: true
      },
      MYR: {
        before: 'RM'
      },
      NOK: {
        before: 'kr'
      },
      NZD: {
        before: '$',
        code: true
      },
      PEN: {
        before: 'S/'
      },
      PHP: {
        before: 'Php'
      },
      PLN: {
        before: 'z'
      },
      QAR: {
        before: '\ufdfc'
      },
      RON: {
        before: 'lei'
      },
      RUB: {
        before: '\u0440\u0443\u0431'
      },
      SAR: {
        before: '\ufdfc'
      },
      SEK: {
        before: 'kr'
      },
      SGD: {
        before: '$',
        code: true
      },
      THB: {
        before: '\u0E3F'
      },
      TRY: {
        before: 'TL'
      },
      TTD: {
        before: 'TT$'
      },
      TWD: {
        before: 'NT$'
      },
      UAH: {
        before: '\u20b4'
      },
      USD: {
        before: '$',
        code: true
      },
      UYU: {
        before: '$U'
      },
      VEF: {
        before: 'Bs'
      },
      VND: {
        before: '\u20ab'
      },
      XCD: {
        before: '$',
        code: true
      },
      ZAR: {
        before: 'R'
      }
    };


    module.exports = function currency(amount, config) {
      var code = config && config.currency || 'USD',
        value = currencies[code],
        before = value.before || '',
        after = value.after || '',
        length = value.length || 2,
        showCode = value.code && config && config.showCode,
        result = amount;

      if (config && config.format) {
        result = before + result.toFixed(length) + after;
      }

      if (showCode) {
        result += ' ' + code;
      }

      return result;
    };

  }, {}],
  16: [function (require, module, exports) {
    'use strict';


    module.exports = (function (window, document) {

      /**
       * Events are added here for easy reference
       */
      var cache = [];

      // NOOP for Node
      if (!document) {
        return {
          add: function () {},
          remove: function () {}
        };
        // Non-IE events
      } else if (document.addEventListener) {
        return {
          /**
           * Add an event to an object and optionally adjust it's scope
           *
           * @param obj {HTMLElement} The object to attach the event to
           * @param type {string} The type of event excluding "on"
           * @param fn {function} The function
           * @param scope {object} Object to adjust the scope to (optional)
           */
          add: function (obj, type, fn, scope) {
            scope = scope || obj;

            var wrappedFn = function (e) {
              fn.call(scope, e);
            };

            obj.addEventListener(type, wrappedFn, false);
            cache.push([obj, type, fn, wrappedFn]);
          },


          /**
           * Remove an event from an object
           *
           * @param obj {HTMLElement} The object to remove the event from
           * @param type {string} The type of event excluding "on"
           * @param fn {function} The function
           */
          remove: function (obj, type, fn) {
            var wrappedFn, item, len = cache.length,
              i;

            for (i = 0; i < len; i++) {
              item = cache[i];

              if (item[0] === obj && item[1] === type && item[2] === fn) {
                wrappedFn = item[3];

                if (wrappedFn) {
                  obj.removeEventListener(type, wrappedFn, false);
                  cache = cache.slice(i);
                  return true;
                }
              }
            }
          }
        };

        // IE events
      } else if (document.attachEvent) {
        return {
          /**
           * Add an event to an object and optionally adjust it's scope (IE)
           *
           * @param obj {HTMLElement} The object to attach the event to
           * @param type {string} The type of event excluding "on"
           * @param fn {function} The function
           * @param scope {object} Object to adjust the scope to (optional)
           */
          add: function (obj, type, fn, scope) {
            scope = scope || obj;

            var wrappedFn = function () {
              var e = window.event;
              e.target = e.target || e.srcElement;

              e.preventDefault = function () {
                e.returnValue = false;
              };

              fn.call(scope, e);
            };

            obj.attachEvent('on' + type, wrappedFn);
            cache.push([obj, type, fn, wrappedFn]);
          },


          /**
           * Remove an event from an object (IE)
           *
           * @param obj {HTMLElement} The object to remove the event from
           * @param type {string} The type of event excluding "on"
           * @param fn {function} The function
           */
          remove: function (obj, type, fn) {
            var wrappedFn, item, len = cache.length,
              i;

            for (i = 0; i < len; i++) {
              item = cache[i];

              if (item[0] === obj && item[1] === type && item[2] === fn) {
                wrappedFn = item[3];

                if (wrappedFn) {
                  obj.detachEvent('on' + type, wrappedFn);
                  cache = cache.slice(i);
                  return true;
                }
              }
            }
          }
        };
      }

    })(typeof window === 'undefined' ? null : window, typeof document === 'undefined' ? null : document);

  }, {}],
  17: [function (require, module, exports) {
    'use strict';


    var forms = module.exports = {

      parse: function parse(form) {
        var raw = form.elements,
          data = {},
          pair, value, i, len;

        for (i = 0, len = raw.length; i < len; i++) {
          pair = raw[i];

          if ((value = forms.getInputValue(pair))) {
            data[pair.name] = value;
          }
        }

        return data;
      },


      getInputValue: function getInputValue(input) {
        var tag = input.tagName.toLowerCase();

        if (tag === 'select') {
          return input.options[input.selectedIndex].value;
        } else if (tag === 'textarea') {
          return input.innerText;
        } else {
          if (input.type === 'radio') {
            return (input.checked) ? input.value : null;
          } else if (input.type === 'checkbox') {
            return (input.checked) ? input.value : null;
          } else {
            return input.value;
          }
        }
      }

    };
  }, {}],
  18: [function (require, module, exports) {
    'use strict';


    var mixin = module.exports = function mixin(dest, source) {
      var value;

      for (var key in source) {
        value = source[key];

        if (value && value.constructor === Object) {
          if (!dest[key]) {
            dest[key] = value;
          } else {
            mixin(dest[key] || {}, value);
          }
        } else {
          dest[key] = value;
        }
      }

      return dest;
    };

  }, {}],
  19: [function (require, module, exports) {
    'use strict';


    function Pubsub() {
      this._eventCache = {};
    }


    Pubsub.prototype.on = function on(name, fn, scope) {
      var cache = this._eventCache[name];

      if (!cache) {
        cache = this._eventCache[name] = [];
      }

      cache.push([fn, scope]);
    };


    Pubsub.prototype.off = function off(name, fn) {
      var cache = this._eventCache[name],
        i, len;

      if (cache) {
        for (i = 0, len = cache.length; i < len; i++) {
          if (cache[i] === fn) {
            cache = cache.splice(i, 1);
          }
        }
      }
    };


    Pubsub.prototype.fire = function on(name) {
      var cache = this._eventCache[name],
        i, len, fn, scope;

      if (cache) {
        for (i = 0, len = cache.length; i < len; i++) {
          fn = cache[i][0];
          scope = cache[i][1] || this;

          if (typeof fn === 'function') {
            fn.apply(scope, Array.prototype.slice.call(arguments, 1));
          }
        }
      }
    };


    module.exports = Pubsub;

  }, {}],
  20: [function (require, module, exports) {
    'use strict';


    var Storage = module.exports = function Storage(name, duration) {
      this._name = name;
      this._duration = duration || 30;
    };


    var proto = Storage.prototype;


    proto.load = function () {
      if (typeof window === 'object' && window.localStorage) {
        var data = window.localStorage.getItem(this._name),
          today, expires;

        if (data) {
          data = JSON.parse(decodeURIComponent(data));
        }

        if (data && data.expires) {
          today = new Date();
          expires = new Date(data.expires);

          if (today > expires) {
            this.destroy();
            return;
          }
        }

        return data && data.value;
      }
    };


    proto.save = function (data) {
      if (typeof window === 'object' && window.localStorage) {
        var expires = new Date(),
          wrapped;

        expires.setTime(expires.getTime() + this._duration * 24 * 60 * 60 * 1000);

        wrapped = {
          value: data,
          expires: expires.toGMTString()
        };

        window.localStorage.setItem(this._name, encodeURIComponent(JSON.stringify(wrapped)));
      }
    };


    proto.destroy = function () {
      if (typeof window === 'object' && window.localStorage) {
        window.localStorage.removeItem(this._name);
      }
    };

  }, {}],
  21: [function (require, module, exports) {
    'use strict';


    var ejs = require('ejs');


    module.exports = function template(str, data) {
      return ejs.render(str, data);
    };


    // Workaround for IE 8's lack of support
    if (!String.prototype.trim) {
      String.prototype.trim = function () {
        return this.replace(/^\s+|\s+$/g, '');
      };
    }

  }, {
    "ejs": 6
  }],
  22: [function (require, module, exports) {
    'use strict';


    var config = require('./config'),
      events = require('./util/events'),
      template = require('./util/template'),
      forms = require('./util/forms'),
      css = require('./util/css'),
      viewevents = require('./viewevents'),
      constants = require('./constants');



    /**
     * Creates a view model.
     *
     * @constructor
     * @param {object} model
     */
    function View(model) {
      var wrapper;

      this.el = wrapper = document.createElement('div');
      this.model = model;
      this.isShowing = false;

      // HTML
      wrapper.id = config.name;
      config.parent.appendChild(wrapper);

      // CSS
      css.inject(document.getElementsByTagName('head')[0], config.styles);

      // JavaScript
      events.add(document, ('ontouchstart' in window) ? 'touchstart' : 'click', viewevents.click, this);
      events.add(document, 'keyup', viewevents.keyup, this);
      events.add(document, 'readystatechange', viewevents.readystatechange, this);
      events.add(window, 'pageshow', viewevents.pageshow, this);
    }


    /**
     * Tells the view to redraw
     */
    View.prototype.redraw = function redraw() {
      events.remove(this.el.querySelector('form'), 'submit', this.model.cart.new_checkout, this.model.cart);
      this.el.innerHTML = template(config.template, this.model);
      events.add(this.el.querySelector('form'), 'submit', this.model.cart.new_checkout, this.model.cart);
    };


    /**
     * Tells the view to show
     */
    View.prototype.show = function show() {
      if (!this.isShowing) {
        css.add(document.body, constants.SHOWING_CLASS);
        this.isShowing = true;
      }
    };


    /**
     * Tells the view to hide
     */
    View.prototype.hide = function hide() {
      if (this.isShowing) {
        css.remove(document.body, constants.SHOWING_CLASS);
        this.isShowing = false;
      }
    };


    /**
     * Toggles the visibility of the view
     */
    View.prototype.toggle = function toggle() {
      this[this.isShowing ? 'hide' : 'show']();
    };


    /**
     * Binds cart submit events to a form.
     *
     * @param {HTMLElement} form
     * @return {boolean}
     */
    View.prototype.bind = function bind(form) {
      var that = this;

      // Don't bind forms without a cmd value
      if (!constants.COMMANDS[form.cmd.value]) {
        return false;
      }

      // Prevent re-binding forms
      if (form.hassbmincart) {
        return false;
      } else {
        form.hassbmincart = true;
      }

      if (form.display) {
        events.add(form, 'submit', function (e) {
          e.preventDefault();
          that.show();
        });
      } else {
        events.add(form, 'submit', function (e) {
          e.preventDefault(e);
          that.model.cart.add(forms.parse(form));
        });
      }

      return true;
    };


    /**
     * Adds an item to the view.
     *
     * @param {number} idx
     * @param {object} data
     */
    View.prototype.addItem = function addItem(idx, data) {
      this.redraw();
      this.show();

      var els = this.el.querySelectorAll('.' + constants.ITEM_CLASS);
      css.add(els[idx], constants.ITEM_CHANGED_CLASS);
    };


    /**
     * Changes an item in the view.
     *
     * @param {number} idx
     * @param {object} data
     */
    View.prototype.changeItem = function changeItem(idx, data) {
      this.redraw();
      this.show();

      var els = this.el.querySelectorAll('.' + constants.ITEM_CLASS);
      css.add(els[idx], constants.ITEM_CHANGED_CLASS);
    };


    /**
     * Removes an item from the view.
     *
     * @param {number} idx
     */
    View.prototype.removeItem = function removeItem(idx) {
      this.redraw();
    };




    module.exports = View;

  }, {
    "./config": 10,
    "./constants": 11,
    "./util/css": 14,
    "./util/events": 16,
    "./util/forms": 17,
    "./util/template": 21,
    "./viewevents": 23
  }],
  23: [function (require, module, exports) {
    'use strict';


    var constants = require('./constants'),
      events = require('./util/events'),
      viewevents;


    module.exports = viewevents = {

      click: function (evt) {
        var target = evt.target,
          className = target.className;

        if (this.isShowing) {
          // Cart close button
          if (className === constants.CLOSER_CLASS) {
            this.hide();
            // Product remove button
          } else if (className === constants.REMOVE_CLASS) {
            this.model.cart.remove(target.getAttribute(constants.DATA_IDX));
            // Product quantity input
          } else if (className === constants.QUANTITY_CLASS) {
            target[target.setSelectionRange ? 'setSelectionRange' : 'select'](0, 999);
            // Outside the cart
          } else if (!(/input|button|select|option/i.test(target.tagName))) {
            while (target.nodeType === 1) {
              if (target === this.el) {
                return;
              }

              target = target.parentNode;
            }

            this.hide();
          }
        }
      },


      keyup: function (evt) {
        var that = this,
          target = evt.target,
          timer;

        if (target.className === constants.QUANTITY_CLASS) {
          timer = setTimeout(function () {
            var idx = parseInt(target.getAttribute(constants.DATA_IDX), 10),
              cart = that.model.cart,
              product = cart.items(idx),
              quantity = parseInt(target.value, 10);

            if (product) {
              if (quantity > 0) {
                product.set('quantity', quantity);
              } else if (quantity === 0) {
                cart.remove(idx);
              }
            }
          }, constants.KEYUP_TIMEOUT);
        }
      },


      readystatechange: function () {
        if (/interactive|complete/.test(document.readyState)) {
          var forms, form, i, len;

          // Bind to page's forms
          forms = document.getElementsByTagName('form');

          for (i = 0, len = forms.length; i < len; i++) {
            form = forms[i];

            if (form.cmd && constants.COMMANDS[form.cmd.value]) {
              this.bind(form);
            }
          }

          // Do the initial render when the buttons are ready
          this.redraw();

          // Only run this once
          events.remove(document, 'readystatechange', viewevents.readystatechange);
        }
      },


      pageshow: function (evt) {
        if (evt.persisted) {
          this.redraw();
          this.hide();
        }
      }

    };

  }, {
    "./constants": 11,
    "./util/events": 16
  }]
}, {}, [9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]);